package com.jz.util.office;

import com.jz.util.office.annotation.HasfCell;
import com.jz.util.office.annotation.HasfTable;
import com.jz.util.office.exception.OfficeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Excel 导出工具类
 */
@Slf4j
public class HasfXSSFWorkbook {

    private Workbook workbook;

    private String fname;
    private static final String DEFAULT_FNAME = "导出数据";
    private static final String DEFAULT_TITLE_DESCRIP = "表格说明：无";
    private List<Object> data;
    private HasfTable hasfTable;
    private static final String DIR = "xlsx";
    private static final String SURFIX = ".xlsx";

    private static final Map<String,String> cacheFieldsMap = new HashMap<>();

    private HasfXSSFWorkbook(){}

    private HasfXSSFWorkbook(Workbook workbook){
        this.workbook = workbook;
    }
    public HasfXSSFWorkbook(Class clazz){
        this.workbook = parseWorkbook(clazz);
        if(clazz != null && null != (hasfTable = (HasfTable) clazz.getAnnotation(HasfTable.class))){
            this.fname = hasfTable.name();
        }
    }
    public HasfXSSFWorkbook(List<Object> data){
        this.data = data;
        this.workbook = parseWorkbook(data);
    }
    private static Workbook parseWorkbook(List<Object> data){
        if(data == null || data.isEmpty()){
            return parseWorkbook("");
        }
        return parseWorkbook(data.get(0).getClass());
    }

    /**
     * 根据class 解析表格
     * @param clazz
     * @return
     */
    private static Workbook parseWorkbook(Class clazz){
        String path = null;
        HasfTable hasfTable = null;
        String descrip = null;
        if(clazz != null && null != (hasfTable = (HasfTable) clazz.getAnnotation(HasfTable.class))){
            path = hasfTable.tempPath();
            descrip = hasfTable.descrip();
        }
        if(descrip == null || descrip.trim().length() == 0){
            descrip = DEFAULT_TITLE_DESCRIP;
        }
        Workbook workbook = parseWorkbook(path);
        Sheet sheet = workbook.createSheet();
        Row titleRow = sheet.createRow(0);
        Cell titleCell = titleRow.createCell(0);
        titleCell.setCellValue(descrip);
        return workbook;
    }

    /**
     * 根据路径查找模板，找不到就new一个新的excel
     * @param path
     * @return
     */
    private static Workbook parseWorkbook(String path){
        if(path == null || path.trim().equals("")){
            return new XSSFWorkbook();
        }else{
            try {
                return new XSSFWorkbook(new ClassPathResource(DIR + File.separator + path + SURFIX).getInputStream());
            } catch (IOException e) {
                return new XSSFWorkbook();
            }
        }
    }
    public Sheet createSheet(String sheetName){
        return workbook.createSheet(sheetName);
    }
    public Sheet createSheet(){
        return workbook.createSheet();
    }
    public Sheet getSheetAt(){
        return workbook.getSheetAt(0);
    }

    /**
     * 获取并创建Sheet
     * @return
     */
    public Sheet getAndCreatSheet(){
        Sheet sheet = getSheetAt();
        if(sheet == null){
            return createSheet();
        }
        return sheet;
    }
    public Sheet getSheetAt(int index){
        return workbook.getSheetAt(0);
    }

    /**
     * 初始化表格
     */
    private void formatData() {
        if(data == null || data.isEmpty()){
            return ;
        }
        Class clazz = data.get(0).getClass();
        // 不会为空,获取字段
        Field[] fields = clazz.getDeclaredFields();
        if(fields.length == 0){
            return;
        }
        Sheet sheet = getSheetAt();
        if(sheet == null){
            sheet = createSheet();
        }
        Row header = sheet.createRow(1);//表头
        List<Field> list = new ArrayList<>();
        //表头遍历并设置值
        for (Field field : fields) {
            // 获取字段得枚举类
            HasfCell hasfCell = field.getAnnotation(HasfCell.class);
            if(null != hasfCell){
                Cell headerCell = header.createCell(list.size());//地点
                list.add(field);
                headerCell.setCellValue(hasfCell.name().length() > 0 ? hasfCell.name():field.getName());
            }
        }
        try {
            for (int rowNumber = 0; rowNumber < data.size(); rowNumber++) {
                Row dataRow = sheet.createRow(rowNumber+2);//创建行--创建新行会覆盖旧行
                Object curData = data.get(rowNumber);
                for (int i = 0; i < list.size(); i++) {
                    Field field = list.get(i);
                    Cell cell = dataRow.createCell(i);
                    field.setAccessible(true);
                    cell.setCellValue(String.valueOf(field.get(curData)));
                }
            }
        } catch (IllegalAccessException e) {
            throw new OfficeException("表格导出错误："+e.getMessage());
        }
    }


    /**
     * 导出
     */
    public void export(){
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = requestAttributes.getResponse();
        if(StringUtils.isBlank(fname)){
            fname = "导出数据";
        }
        String filename = fname;
        long begin = System.currentTimeMillis();
        formatData();
        try {
            fname = new String(fname.getBytes("GBK"), "iso8859-1");
            OutputStream os = response.getOutputStream();
            response.reset();
            response.setHeader("Content-disposition", "attachment; filename=" + fname + ".xlsx");
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/msexcel");
            workbook.write(os);
            os.close();
        }  catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        log.info("导出到表，【{},时间(秒):{}】",filename,((double) (end - begin) / 1000));
    }


}
